package com.gitee.l0km.casban;

import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import java.net.URL;
import java.util.LinkedHashSet;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import com.gitee.l0km.com4j.basex.annotations.ActiveOnClass;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;

/**
 * 基于Spring {@link PathMatchingResourcePatternResolver}实现资源扫描
 * @author guyadong
 *
 */
@ActiveOnClass(PathMatchingResourcePatternResolver.class)
public class SpringResourceScanner extends PackageScanner{
	public static final SpringResourceScanner SPRING_PACKAGE_SCANNER = new SpringResourceScanner();
	private static final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
	private static final String CLASS_SUFFIX = ".class";

	LinkedHashSet<URL> getResources(String rootDirPath, String suffix) throws IOException {
		String path = checkNotNull(rootDirPath, "rootDirPath must not be null");
		String locationPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + path;
		if(null != suffix) {
			locationPattern +="**/*"+suffix;
		}
		Resource[] resources = resolver.getResources(locationPattern);
		return FluentIterable.from(resources)
				.transform(URL_BUILDER)
				.copyInto(new LinkedHashSet<URL>());
	}
	/**
	 * 扫描指定包名下的所有类
	 * @param packagename
	 * @throws IOException
	 */
	@Override
	protected LinkedHashSet<Class<?>> getClasses(String packagename, Predicate<String> excludePackageFilter) throws IOException {
		checkNotNull(packagename, "packagename must not be null");
		Predicate<String> packageFilter = buildPackageFilter(packagename,excludePackageFilter);
		String path = CommonFunctions.packageNameToPathFun().apply(packagename);
		LinkedHashSet<URL> rootDirs = getResources(path,null);
		LinkedHashSet<URL> urls = getResources(path, CLASS_SUFFIX);
		ImmutableSet<String> rootPrefixes = FluentIterable.from(rootDirs)
				.transform(CommonFunctions.removeSuffixFun(path)).toSet();
		return FluentIterable.from(urls)
				.transform(new CLassNameFromURL(rootPrefixes))
				.filter(packageFilter)
				.transform(CLASS_FORNAME_GET_FUN)
				.copyInto(new LinkedHashSet<Class<?>>());
	}
	private static final Function<Resource, URL> URL_BUILDER = new Function<Resource, URL>(){

		@Override
		public URL apply(Resource input) {
			try {
				return input.getURL();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	};
	private class CLassNameFromURL implements Function<URL, String>{
		private final Iterable<String> rootPrefixes;
		public CLassNameFromURL(Iterable<String> rootPrefixes) {
			this.rootPrefixes = rootPrefixes;
		}
		@Override
		public String apply(URL input) {
			String url = input.toString();
			for(String prefix : rootPrefixes) {
				if(url.startsWith(prefix)) {
					String p = url.substring(prefix.length(),url.length()-CLASS_SUFFIX.length());
					return FILE_SEPARATOR_MATCHER.replaceFrom(p, '.');
				}
			}
			throw new IllegalArgumentException("INVALID URL "+input);
		}
	}
}
